import asammdf
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.figure import Figure
import matplotlib
import os
import re
import pathlib
matplotlib.rcParams['font.family'] = 'SimHei'  # 例如使用 'SimHei' 字体
matplotlib.rcParams['axes.unicode_minus'] = False  # 正确显示负号


class Model:
    def __init__(self):
        self.report = []  # 用于存储分析结果
        self.keyframe = -1
        self.last_zero_time = -1
        self.manual_intervention_time = -1
        self.lgt_p = []
        self.decel_p = []
    def load_mf4(self, file_path):
        # 代码来加载和解析MF4文件
        self.mdf_file = asammdf.MDF(file_path)
        for signal in self.mdf_file.channels_db:
            print(signal)

    def export_mf4_as_mat(self,file_path):
        # 导入路径
        dir = file_path
        print(dir)
        file_names = list(pathlib.Path(dir).glob('*.mf4'))
        save_path = dir
        print(file_names)
        # os.mkdir(save_path)
        # 逐个转换格式
        for file_name in file_names:
            print(file_name)
            mdf = asammdf.MDF(os.path.join(dir,file_name))
            mdf.export("mat",os.path.join(save_path,file_name))
            print(file_name,"done")
    def analyze_data(self):
        # 数据分析逻辑
        pass
# -----------------------------------AEB&FCW关键帧分析--------------------------------------
    def analyze_aeb_warning_signal(self,signal):# -> tuple[Literal['Key frame :'], Any] | Literal['No change detected in the signal.']:
        # 提取out_ADCU_AEBWarning信号
        signal = self.mdf_file.get(signal)
        timestamps = signal.timestamps
        values = signal.samples

        # 寻找第一次变化的时刻
        first_change_time = self.find_first_change(timestamps, values)
        if first_change_time is not None:
            self.keyframe = first_change_time
            return "Key frame :", first_change_time
        else:
            return "No change detected in the signal."
        # 寻找触发后车速归零的时刻
# -----------------------------------AEB主目标纵向距离分析--------------------------------------
    def analyze_posnlgt_signal(self):
        signal_name = "Disp_AEBObj_PrimTarIntv_PosnLgt"
        signal = self.mdf_file.get(signal_name)
        values = signal.samples

        # 检查纵向距离是否异常
        if any(value < 4.1 for value in values):
            return f"出现纵向距离异常，小于 {4.1}m。"
        else:
            return "纵向距离正常。"
# -----------------------------------自车速度降分析--------------------------------------
    def calculate_speed_reduction(self):
        v_signal_name = "in_IPB_vehicleSpeed"
        brake_signal_name = "ipb_brakePedalStatus"
        start_time = self.keyframe
        end_time = self.last_zero_time
        # 提取速度信号和踏板信号
        v_signal = self.mdf_file.get(v_signal_name)
        brake_signal = self.mdf_file.get(brake_signal_name)

        # 直接在时间戳数组中找到开始和结束时间的索引
        start_index = np.searchsorted(v_signal.timestamps, start_time, side='left')
        end_index = np.searchsorted(v_signal.timestamps, end_time, side='right') - 1
        print(start_index)
        # 检查在 AEB 触发期间是否有人工干预刹车
        manual_intervention_time = None
        for i, (t, pressed) in enumerate(zip(brake_signal.timestamps, brake_signal.samples)):
            
            if pressed==b'PRESSED' and start_time < t < end_time:
                manual_intervention_time = t
                print("发现人工介入",t)
                break
        self.manual_intervention_time = manual_intervention_time
        # 如果有人工干预，找到最接近的索引
        if manual_intervention_time is not None:
            final_index = np.searchsorted(v_signal.timestamps, self.manual_intervention_time, side='right') - 1
            print("有人工干预")
            print(final_index)
        else:
            final_index = np.searchsorted(v_signal.timestamps, end_time, side='right') - 1

        # 确保 final_index 不超出数组的界限
        final_index = min(final_index, len(v_signal.samples) - 1)

        # 计算速度降低
        initial_speed = v_signal.samples[start_index]
        final_speed = v_signal.samples[final_index]
        print(start_index,final_index)
    
        speed_reduction = initial_speed - final_speed
        # 如果是 Disp_AEBObj_PrimTarIntv_VLgt 信号，计算速度降低并添加到评论

        return f"\nAEB功能激活期间产生了速度降：{speed_reduction:.3f} m/s（{initial_speed:.3f}->{final_speed:.3f}）"
# -----------------------------------执行器分析-----------------------------------------------
    def find_minmaxp(self,signal_name):
        minv = []
        maxv = []
        signal = self.mdf_file.get(signal_name)
        print(len(signal.timestamps))
        for i, (t, lgt_a) in enumerate(zip(signal.timestamps, signal.samples)):
           # 尋找極小值
           if i>1 and i<len(signal.timestamps)-1:#不要邊界值以避免數組越界
                # 比相鄰值都大的值是極大值
                # print(i)
                if self.keyframe<signal.timestamps[i]<self.last_zero_time:
                    case1 = signal.samples[i]>signal.samples[i-1] and signal.samples[i]>signal.samples[i+1]
                    case2 = signal.samples[i]>=signal.samples[i-1] and signal.samples[i]>signal.samples[i+1]
                    case3 = signal.samples[i]>signal.samples[i-1] and signal.samples[i]>=signal.samples[i+1]
                    if case1 or case2 or case3:
                        maxv.append(t)
                    # 比相鄰值都小的值是極小值
                    case1 = signal.samples[i]<signal.samples[i-1] and signal.samples[i]<signal.samples[i+1]
                    case2 = signal.samples[i]<=signal.samples[i-1] and signal.samples[i]<signal.samples[i+1]
                    case3 = signal.samples[i]<signal.samples[i-1] and signal.samples[i]<=signal.samples[i+1]
                    if case1 or case2 or case3:
                        minv.append(t)
        return minv, maxv
    def IPB_Analysis(self):
        # 尋找極值點
        lgt_a_name = 'in_LgtA'
        decel_a_name = 'out_ADCU_AEB_DECEL_CMD'
        lgt_min, lgt_max = self.find_minmaxp(lgt_a_name)
        decel_min, decel_max = self.find_minmaxp(decel_a_name)
        # 删除请求减速度极值点之前得极值点
        print(lgt_min)
        for i,t in enumerate(lgt_min):
            if t>decel_min[0]:
                del lgt_min[:i]
                break
        for i,t in enumerate(lgt_max):
            if t>decel_max[0]:
                del lgt_max[:i]
                break       
        print(lgt_min)  
        print(decel_min)          
        self.lgt_min = lgt_min
        self.decel_min = decel_min
        self.lgt_max = lgt_max
        self.decel_max = decel_max
        L_min = min(len(lgt_min),len(decel_min))
        L_max = min(len(lgt_max),len(decel_max))
        delta_decel = []
        delta_acc = []
        print(L_min,L_max)
        if L_min > 0:
            for i in range(0,L_min):
                print(lgt_min[i],decel_min[i])
                delta_decel.append(abs(lgt_min[i]-decel_min[i]))
        if L_max > 0:
            for i in range(0,L_max):
                delta_acc.append(abs(lgt_max[i]-decel_max[i]))
        return "IPB 波谷延迟:"+str(delta_decel)+'\n'+"IPB 波峰延迟:"+str(delta_acc)
# -----------------------------------TTC分析-------------------------------------------------
    def TTC_Analysis(self):
        pass
        return "TTC"
# -----------------------------------AEB&FCW触发状态分析--------------------------------------
    def analyze_aeb_fcw_trigger(self, signaln):
        signal = self.mdf_file.get(signaln)
        timestamps = signal.timestamps
        values = signal.samples

        # 初始化状态
        aeb_triggered = False
        fcw_triggered = False
        trigger_sequence = []
        trigger_times = []

        # 分析信号以确定触发状态和触发过程
        for i in range(1, len(values)):
            if values[i] in [3, 5] and not aeb_triggered:
                aeb_triggered = True
                trigger_sequence.append(('AEB', timestamps[i]))
            elif values[i] in [1, 4] and not fcw_triggered:
                fcw_triggered = True
                trigger_sequence.append(('FCW', timestamps[i]))

        # 计算触发间隔
        for i in range(1, len(trigger_sequence)):
            prev_event, prev_time = trigger_sequence[i - 1]
            curr_event, curr_time = trigger_sequence[i]
            trigger_times.append((f"{prev_event} to {curr_event}", curr_time - prev_time))

        # 输出触发状态和触发过程
        trigger_status = f"AEB {'触发' if aeb_triggered else '未触发'}, FCW {'触发' if fcw_triggered else 'not 未触发'}."
        trigger_process = " -> ".join([f"{event} after {delta:.2f} seconds" for event, delta in trigger_times])
        recommendations = "发现多次触发,请分析模型." if len(
            trigger_times) > 1 else "AEB触发过程正常."

        return trigger_status + ',' + trigger_process + ',' + recommendations
# -----------------------------------测试终止时刻分析--------------------------------------
    def find_last_zero_speed(self):
        speed_signal = self.mdf_file.get("in_IPB_vehicleSpeed")
        timestamps = speed_signal.timestamps
        values = speed_signal.samples

        last_zero_time = None
        for i in range(len(values) - 1, 0, -1):
            if values[i] == 0 and values[i - 1] != 0:
                last_zero_time = timestamps[i]
                break
        if last_zero_time is not None:
            self.last_zero_time = last_zero_time
        else:
            self.last_zero_time = timestamps[-1]
        return "end time:", last_zero_time

    def find_first_change(self, timestamps, values):
        # 寻找第一次变化的时刻
        for i in range(1, len(values)):
            if values[i] != values[i - 1]:
                return timestamps[i]
        return None
# -----------------------------------场景定位--------------------------------------
    def generate_report(self):
        # 生成报告的逻辑

        self.report.append(self.analyze_aeb_warning_signal("ADCU_AEBWarning"))
        self.report.append(self.find_last_zero_speed())
        # 以下是生成报告文件的代码，这里仅为示例
        # 实际中您可能需要将报告内容写入文件或以其他方式输出
        print("Generated Report:\n", self.report)
# -----------------------------------关键帧信号绘制--------------------------------------
    def plot_signal_around_key_frames(self, signal_name):
        # signal_name 是您要绘制的信号名称
        # window 是关键帧前后的时间窗口，单位是秒

        signal = self.mdf_file.get(signal_name)
        timestamps = signal.timestamps
        values = signal.samples

        start_time = self.keyframe - 1
        end_time = self.last_zero_time + 1

        # 提取前后3秒的数据
        mask = (timestamps >= start_time) & (timestamps <= end_time)
        signal_window = values[mask]
        timestamps_window = timestamps[mask]

        # 绘制曲线图
        # 创建Figure对象而不是直接使用plt.figure()
        fig = Figure(figsize=(10, 4))
        ax = fig.add_subplot(111)
        ax.plot(timestamps_window, signal_window)
        ax.set_title(f"{signal_name} at {self.keyframe:.2f}-{self.last_zero_time:.2f} s")
        ax.set_xlabel("Time (s)")
        ax.set_ylabel("Signal Value")
        return fig, ax
# -----------------------------------信号关键区域分析--------------------------------------
    def find_non_default_range_within_window(self, signal_name, default_value):

        start_time = self.keyframe - 1
        end_time = self.last_zero_time + 1
        signal = self.mdf_file.get(signal_name)
        timestamps = signal.timestamps
        values = signal.samples

        # 初始化为窗口的边界值
        non_default_start, non_default_end = start_time, end_time

        # 在指定的窗口内寻找非默认值的开始和结束时间
        for i in range(len(values)):
            if start_time <= timestamps[i] <= end_time and values[i] != default_value:
                non_default_start = timestamps[i]
                break

        for i in range(len(values) - 1, -1, -1):
            if start_time <= timestamps[i] <= end_time and values[i] != default_value:
                non_default_end = timestamps[i]
                break

        # 提取前后的数据
        mask = (timestamps >= non_default_start) & (timestamps <= non_default_end)
        signal_window = values[mask]
        timestamps_window = timestamps[mask]

        # 绘制曲线图
        # 创建Figure对象而不是直接使用plt.figure()
        fig = Figure(figsize=(10, 4))
        ax = fig.add_subplot(111)
        ax.plot(timestamps_window, signal_window)

        if signal_name=='out_ADCU_AEB_DECEL_CMD':
            signl_2 = self.mdf_file.get('in_LgtA')
            timestamps2 = signl_2.timestamps
            values2 = signl_2.samples *10
            mask = (timestamps2 >= non_default_start) & (timestamps2 <= non_default_end)
            signal2_window = values2[mask]
            timestamps2_window = timestamps2[mask]
            ax.plot(timestamps2_window, signal2_window)

        ax.set_title(f"{signal_name} at {non_default_start:.2f}-{non_default_end:.2f} s")
        ax.set_xlabel("Time (s)")
        ax.set_ylabel("Signal Value")
        return fig, ax, non_default_start, non_default_end
